from operator import itemgetter
import logging
from scipy import average
from agentinfo import AgentInfo

class Game(object):
    """An interated IDS game consisting of multiple rounds."""
    
    def __init__(self, agents, world, verbose=False):
        """
        Keyword arguments:
        agents -- a list of agent instances
        world -- a World instance
        """
        self.A = agents   
        self.world = world
        world.setup_agents(self.A)
        self.round = 0
        # a list to store the history of outcomes for each round and each agent
        #  format is H[round number][agent id]{'attribute':'value'}
        self.H = []
        self.verbose = verbose
        
    def _play_round(self,verbose=False):
        """Play a single round/game."""

        self.round += 1
        
        # initialize history for this round
        self.H.append([{} for i in self.A])
        for i,agent in enumerate(self.A):
            # compute start balance
            if len(self.H) == 1:
                self.H[-1][i]['start_balance'] = self.world.start_balance
            else:
                self.H[-1][i]['start_balance'] = self.H[-2][i]['end_balance']   
 
        # record decision of each agent (invest or not invest) 
        decisions = []
        for i,agent in enumerate(self.A):           
            decisions.append(agent.decide(i,AgentInfo(i,self)))

        # compute outcomes and update balances for each agent        
        outcome,negevent = self.world.outcomes(decisions)
          
        # record results and stats
        for i,agent in enumerate(self.A):
            self.H[-1][i]['invested'] = decisions[i]
            self.H[-1][i]['negevent'] = negevent[i]
            self.H[-1][i]['outcome'] = outcome[i]
            self.H[-1][i]['end_balance'] = self.H[-1][i]['start_balance'] + outcome[i]
            self.H[-1][i]['num_invested'] = self.world.num_invested(i,decisions)
            self.H[-1][i]['neighbors'] = self.world.neighbors(i)
            self.H[-1][i]['neighborhood_size'] = len(self.world.neighbors(i))+1
        
        # update state of world
        self.world.next_round()
        
        # report
        if self.verbose:
            if self.round == 1:
                self._print("\nGAME WITH %s AGENTS\n"%len(self.A))
                self._print('Parameters:\n'+self.world.parameters_as_str())
                self._print('Agent types:\n'+','.join([x.name() for x in self.A])+'\n')
                self._print('Aggregate results for each round:')
                self._print('Round, Average outcome, Percent investing')
            tmp = '%s,'%self.round               
            tmp += '%.02f,'%average([x['outcome'] for x in self.H[-1]])
            tmp += '%.02f'%average(decisions)
            self._print(tmp)
        
    def play(self):
        """Play all rounds in this game and return a list of final scores."""
        while self.round < self.world.num_rounds:
            self._play_round()

        # report
        if self.verbose:
            results = [['%s-%s'%(a.name(),i),self.H[-1][i]['end_balance']]
                        for i,a in enumerate(self.A)]        
            results.sort(key=itemgetter(1),reverse=True)
            self._print('\nFinal rankings:')
            for i,x in enumerate(results):
                self._print('%s. %s: %.02f' % (i+1,x[0],x[1]))
                
        return [x['end_balance'] for x in self.H[-1]]

    def _print(self, text):
        """Override if necessary to direct output to a different destination"""
        logging.info(text)
                     
    def export_data(self,filename,path,format="cvs"):
        """Not yet implemented."""
        pass
